package log

import (
	"sync"
	"io"
	"os"
	"time"
	"runtime"
	"fmt"
	"strconv"
)

type Logger struct {
	mu sync.Mutex
	out io.Writer
}

var output = func() *os.File {
	perm, _ := strconv.ParseInt("0666", 8, 64)
	file := "/tmp/home.log"
	fd, err := os.OpenFile(file, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(perm))
	if err != nil {
		return nil
	}

	return fd
}()

func (l *Logger) Output(calldepth int, s string) error {
	// 北京时间 +8
	now := time.Now().Add(time.Hour * 8).Format("01/02 15:04:05.999")
	l.mu.Lock()
	defer l.mu.Unlock()

	_, file, line, ok := runtime.Caller(calldepth)
	if !ok {
		file = "???"
		line = 0
	} else {
		short := file
		for i := len(file) - 1; i > 0; i-- {
			if file[i] == '/' {
				short = file[i+1:]
				break
			}
		}
		file = short
	}

	log := fmt.Sprintf("%-17s %s:%d %s", now, file, line, s)
	l.out.Write([]byte(log))
	if output != nil {
		output.Write([]byte(log))
	}

	return nil
}

var std = &Logger{out: os.Stderr}

func Printf(format string, v ...interface{}) {
	std.Output(2, fmt.Sprintf(format, v...))
}

func Println(v ...interface{}) {
	std.Output(2, fmt.Sprintln(v...))
}

func Debug(format string, v ...interface{}) {
	std.Output(2, fmt.Sprintf(format + "\n", v...))
}

func Info(format string, v ...interface{}) {
	std.Output(2, fmt.Sprintf("\033[32;1m" + format + "\033[0m\n", v...))
}

func Notice(format string, v ...interface{})  {
	std.Output(2, fmt.Sprintf("\033[33;1m" + format + "\033[0m\n", v...))
}

func Error(format string, v ...interface{})  {
	std.Output(2, fmt.Sprintf("\033[31;1m" + format + "\033[0m\n", v...))
}

func Fatal(v ...interface{}) {
	std.Output(2, fmt.Sprint(v...))
	os.Exit(1)
}

func Panic(v ...interface{}) {
	s := fmt.Sprint(v...)
	std.Output(2, s)
	panic(s)
}

func Panicln(v ...interface{}) {
	s := fmt.Sprintln(v...)
	std.Output(2, s)
	panic(s)
}

